<template>
    <div class="stats" ref="statsRef"></div>
    <div class="container" ref="containerRef"></div>
</template>

<script setup>

import { ref, reactive, onMounted, onActivated, watch } from 'vue'
import {
    Scene, PerspectiveCamera, WebGLRenderer, Color, AxesHelper, PlaneGeometry, Mesh,
    BoxGeometry, SphereGeometry, SpotLight, MeshLambertMaterial,
    AmbientLight,
    PointLight,
    CameraHelper
} from 'three'
import * as dat from 'dat.gui'

// 性能监控star==================================>性能监控
import Stats from 'stats.js'
const stats = new Stats()
stats.showPanel(0)
stats.dom.style.top = '50px'
const statsRef = ref(null)
// 性能监控end==================================>性能监控

const containerRef = ref(null)
// 交互控制star==================================>交互控制
const controlRef = ref({
    rotationSpeed: 0.02,
    bouncingSpeed: 0.03,
    ambientColor: "#0c0c0c", //环境光添加
    pointColor: '#ccffcc', // 点光源添加
    distance: 100, // 点光源添加
    intensity: 1, // 点光源添加
    debug:false,  // 聚光灯添加
    target:'plane'  // 聚光灯添加
})
// 交互控制end==================================>交互控制



// 创建一个场景
const scene = new Scene()


// 创建一个摄像机，所谓摄像机就是模拟人眼从哪个视角（位置开始观察）
// 参数一为角度，参数二为框高比，参数三位观察的最近的距离，参数四为观察最远距离
const camera = new PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000)

// 设置相机摆放的位置分别代表x，y，z的坐标
camera.position.set(-30, 40, 30)

// 设置相机的朝向
camera.lookAt(scene.position)

// 初始化渲染,设置渲染的容器
const renderer = new WebGLRenderer()
// 设置渲染的颜色，这个颜色也可以放rgb的颜色
renderer.setClearColor(new Color(0xeeeeee))
renderer.setSize(window.innerWidth, window.innerHeight)

// 设置渲染器容器支持阴影star==================================>材质和关照的使用
renderer.shadowMap.enabled = true
// 设置渲染器容器支持阴影end==================================>材质和关照的使用

// 创建一个灯光star==================================>材质和关照的使用
// 设置颜色
const spotLight = new SpotLight(0xffffff)
// 设置是否阴影
spotLight.castShadow = true
// 设置灯光位置
spotLight.position.set(-40, 60, -10)
// 设置灯光强度
spotLight.intensity = 10000;
scene.add(spotLight)
// 点光源增加
spotLight.lookAt(scene.position)
// 创建一个灯光end==================================>材质和关照的使用


// 为场景增加一个右手坐标系,参数代表坐标系大小
const axes = new AxesHelper(20)
scene.add(axes)



// 添加一个平面材质 参数为材质大小
const planeGeometry = new PlaneGeometry(60, 20)
// 设置材质颜色
const meshBasicMaterial = new MeshLambertMaterial({ color: 0xcccccc }) // 修改材质为MeshLambertMaterial=======>材质和关照的使用
const plane = new Mesh(planeGeometry, meshBasicMaterial)
// 设置材质支持阴影star==================================>材质和关照的使用
plane.receiveShadow = true
// 设置材质支持阴影end==================================>材质和关照的使用
// 设置材质位置
plane.rotation.x = -0.5 * Math.PI
// plane.position.x = 15
// plane.position.y = 0
// plane.position.z = 0
// 增加材质
scene.add(plane)

// 继续增加一个立体矩形材质(这是一个立体的几何体)，三个参数分别代表长宽高，现在三个值相同那么就表示是一个正方体
const cubeGeometry = new BoxGeometry(4, 4, 4)
// wireframe表示填充否，True不填充，false填充
const cubeMaterial = new MeshLambertMaterial({
    color: 0xff0000,
    wireframe: false  // 修改wireframe为false===========>材质和关照的使用
}) // 修改材质为MeshLambertMaterial=======>材质和关照的使用
const cube = new Mesh(cubeGeometry, cubeMaterial)
// 设置材质支持阴影star==================================>材质和关照的使用
cube.castShadow = true
// 设置材质支持阴影end==================================>材质和关照的使用
cube.position.set(-2, 4, 6)
scene.add(cube)

// 继续增加一个球体材质
const sphereGeometry = new SphereGeometry(4)
const sphereMaterial = new MeshLambertMaterial({
    color: 0x7777ff,
    wireframe: false  // 修改wireframe为false===========>材质和关照的使用
})
const sphere = new Mesh(sphereGeometry, sphereMaterial)
// 设置材质支持阴影star==================================>材质和关照的使用
sphere.castShadow = true
// 设置材质支持阴影end==================================>材质和关照的使用
sphere.position.x = 20
sphere.position.y = 4
sphere.position.z = 2
scene.add(sphere)

// 点光源添加
// 添加一个小球材质
const lookAtGeom = new SphereGeometry(1)
const lookAtMesh = new Mesh(
    lookAtGeom,
    new MeshLambertMaterial({
        color: 0xff0000
    })
)
scene.add(lookAtMesh)
// 设置光源
const pointLight = new PointLight(controlRef.value.pointColor)
pointLight.distance = 200
pointLight.intensity = 300
pointLight.position.copy(lookAtMesh.position)
scene.add(pointLight)

// 增加动画star==================================>材质和关照增加动画
let step = 0
function renderScene() {
    // 性能监控end==================================>性能监控
    stats.update()
    // 性能监控end==================================>性能监控
    cube.rotation.x += controlRef.value.rotationSpeed
    cube.rotation.y += controlRef.value.rotationSpeed
    cube.rotation.x += controlRef.value.rotationSpeed

    step += 0.02
    // sphere.position.x = 20 + 10 * Math.cos(step)
    // sphere.position.y = 2 + 10 * Math.abs(Math.sin(step))

    // 设置点光源动画
    lookAtMesh.position.set(
        20 + 10 * Math.cos(step),
        5 + 10 * Math.abs(Math.sin(step)),
        10 * Math.cos(step)
    )
    // 聚光灯添加
    spotLight.position.copy(lookAtMesh.position)
    // 对页面渲染的每一帧的时候增加动画渲染
    requestAnimationFrame(renderScene)
    renderer.render(scene, camera)
}

renderScene()
// 增加动画end==================================>材质和关照增加动画

// 环境光
const ambientlight = new AmbientLight(controlRef.value.ambientColor)
scene.add(ambientlight)
//环境光添加
watch(() => controlRef.value.ambientColor, (n) => {
    ambientlight.color = new Color(n)
})
// 聚光灯添加
watch(() => controlRef.value.pointColor, (n) => {
    spotLight.color = new Color(n)
})
// 聚光灯添加
watch(() => controlRef.value.distance, (n) => {
    spotLight.distance = n
})
// 聚光灯添加
watch(() => controlRef.value.intensity, (n) => {
    spotLight.intensity = n
})
// 聚光灯添加
const cameraHelper = new CameraHelper(spotLight.shadow.camera)
// 聚光灯添加
watch(() => controlRef.value.debug, (n) => {
    if(n) {
        scene.add(cameraHelper)
    } else {
        scene.remove(cameraHelper)
    }
})
// 聚光灯添加
watch(() => controlRef.value.target, (n) => {
    if(n=='cube') {
        spotLight.target = cube
    } else if (n=='sphere') {
        spotLight.target = sphere
    } else {
        spotLight.target = plane
    }
})
// 交互控制end==================================>交互控制
function initGUI() {
    if (document.querySelectorAll(".dg.ac>.dg.main.a").length == 0) {
        const gui = new dat.GUI
        gui.add(controlRef.value, 'rotationSpeed', 0, 0.5)
        gui.add(controlRef.value, 'bouncingSpeed', 0, 0.5)
        gui.addColor(controlRef.value, 'ambientColor')  //环境光添加
        gui.addColor(controlRef.value, 'pointColor') // 点光源添加
        gui.add(controlRef.value, 'distance', 1, 1000) // 点光源添加
        gui.add(controlRef.value, 'intensity', 1, 1000) // 点光源添加
        gui.add(controlRef.value, 'debug') // 聚光灯添加
        gui.add(controlRef.value, 'target',['plane','cube','sphere']) // 聚光灯添加
    }
}



initGUI()
// 交互控制end==================================>交互控制

onMounted(() => {

    // 性能监控end==================================>性能监控
    statsRef.value?.appendChild(stats.dom)
    // 性能监控end==================================>性能监控
    // 将渲染出来的容器放入到页面中 
    containerRef.value?.appendChild(renderer.domElement)
    // 增加场景,参数一为场景，参数二维相机（其实就是想前面创建的场景跟相机增加进来渲染）
    renderer.render(scene, camera)

})
onActivated(() => {

})


</script>

<style lang='less' scoped>
.container {
    height: 100%;
    width: 100%;
}
</style>